package ciprian.google;

/**
 * @author Ciprian Ursu
 * 
 * mac debug api key: "0fsuQtFxEOGPI8O_9cOkKZb7PIOuvaWqtz9xn3Q"
 * 
 */

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;

import ciprian.google.R;
import ciprian.google.location_mgr.MapPoint;
import ciprian.google.parser.GPXXMLParser;
import ciprian.google.parser.PointsToGPX;
import ciprian.google.provider.TransportContentProvider;
import ciprian.google.provider.TransportContentProvider.MySQLiteDBHelper;
import ciprian.google.transport.NetworkUtilities;
import ciprian.google.utils.LowPassFilter;
import ciprian.google.utils.Prefs;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

// maps API key
// macbook pro: 0fsuQtFxEOGPzSnmQiTrv6DpiW4-Dqom1SA1g9w
// macbook pro XING: 0fsuQtFxEOGMlpB35t0FEpM5rHyOe50icBU6CFw

public class MapViewActivity extends MapActivity implements OnClickListener {
    protected static String TAG = "MapViewActivity";

    private MapController mapController;
    private MapView mapView;
    private MapOverlay mapOverlay;
    private MyLocationOverlay myLocOverlay;
    private ArrayList<MapPoint> mapPoints;

    private byte applicationMode;
    private String routeFilePath;

    private Double selectedLatitude;
    private Double selectedLongitude;
    private Location lastKnownLocation = null;
    private LocationManager lm;
    private MyLocationListener locationListener;
    private String provider;

    private SharedPreferences settings;
    private int timeResolution;
    private boolean satelliteStatus;

    static final int DEFAULT_ZOOM_LEVEL = 15;
    static final int DIALOG_POI_ID = 0;

    public static final int ADD_POI_REQUEST = 0;

    private Toast infoToast;

    // Magnetic field sensor related.
    private SensorManager mSensorManager;
    private Sensor accelerometer;
    private Sensor magnetometer;
    private float azimuth;

    // Overlays bitmap to keep in memory.
    private Bitmap bmpIntermediatePoint;
    private Bitmap bmpPOIHut;
    private Bitmap bmpPOIPeak;
    private Bitmap bmpPOICamping;
    private Bitmap bmpPOIShelter;
    private Bitmap bmpPOINiceToView;
    private Bitmap bmpCurrentLocation;
    private Paint mPaint = new Paint();

    private ImageView animateToMeImageView;

    private boolean mDrawRoute = true;

    /**
     * MapOverlay BEGIN
     */
    class MapOverlay extends Overlay {
        @Override
        public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
            super.draw(canvas, mapView, shadow);

            // Display the POIs and intermediate points from the gpx file.
            if (null != mapPoints) {
                Point previousPoint = null;
                Path path = new Path();

                for (int i = 0; i < mapPoints.size(); i++) {
                    Point screenPoint = new Point();

                    GeoPoint curPoint = new GeoPoint((int) (mapPoints.get(i)
                            .getLatitude() * 1E6),
                            (int) (mapPoints.get(i).getLongitude() * 1E6));

                    if (mapView.getProjection().toPixels(curPoint, screenPoint) != null
                            && (mDrawRoute || isCurrentLocationVisible(mapView, curPoint))) {

                        switch (mapPoints.get(i).getType()) {
                        case MapPoint.INTERMEDIATE_POINT:
                            if (previousPoint != null && mDrawRoute) {
                                // build the route path
                                path.moveTo(previousPoint.x, previousPoint.y);
                                path.lineTo(screenPoint.x, screenPoint.y);
                            } else {
                                canvas.drawBitmap(bmpIntermediatePoint, screenPoint.x,
                                        screenPoint.y - bmpIntermediatePoint.getHeight(),
                                        null);
                            }

                            previousPoint = screenPoint;
                            break;
                        case MapPoint.POI_HUT:
                            canvas.drawBitmap(bmpPOIHut,
                                    screenPoint.x - (bmpPOIHut.getWidth() / 2),
                                    screenPoint.y - (bmpPOIHut.getHeight() / 2), null);
                            break;
                        case MapPoint.POI_PEAK:
                            canvas.drawBitmap(bmpPOIPeak,
                                    screenPoint.x - (bmpPOIPeak.getWidth() / 2),
                                    screenPoint.y - (bmpPOIPeak.getHeight() / 2), null);
                            break;
                        case MapPoint.POI_CAMPING:
                            canvas.drawBitmap(bmpPOICamping, screenPoint.x
                                    - (bmpPOICamping.getWidth() / 2), screenPoint.y
                                    - (bmpPOICamping.getHeight() / 2), null);
                            break;
                        case MapPoint.POI_SHELTER:
                            canvas.drawBitmap(bmpPOIShelter, screenPoint.x
                                    - (bmpPOIShelter.getWidth() / 2), screenPoint.y
                                    - (bmpPOIShelter.getHeight() / 2), null);
                            break;
                        case MapPoint.POI_NICE_TO_VIEW:
                            canvas.drawBitmap(bmpPOINiceToView, screenPoint.x
                                    - (bmpPOINiceToView.getWidth() / 2), screenPoint.y
                                    - (bmpPOINiceToView.getHeight() / 2), null);
                            break;

                        default:
                            canvas.drawBitmap(bmpIntermediatePoint, screenPoint.x,
                                    screenPoint.y - bmpIntermediatePoint.getHeight(),
                                    null);
                        }
                    }
                }

                if (!path.isEmpty())
                    canvas.drawPath(path, mPaint);
            }

            // check if the user selected the native
            // compass & my location indicators.
            if (!settings.getBoolean(Constants.MY_LOC_OVERLAY_STATUS, false)) {
                // Display the current/last known position
                if (null != lastKnownLocation) {
                    int w = bmpCurrentLocation.getWidth();
                    int h = bmpCurrentLocation.getHeight();

                    // Rotate so that the arrow points North.
                    Matrix mtx = new Matrix();

                    float rotation = azimuth * 360 / (2 * 3.14159f);

                    mtx.postRotate(rotation);

                    // Rotating Bitmap
                    Bitmap rotatedBMP = Bitmap.createBitmap(bmpCurrentLocation, 0, 0, w,
                            h, mtx, true);

                    GeoPoint currentGeoPoint = new GeoPoint(
                            (int) (lastKnownLocation.getLatitude() * 1E6),
                            (int) (lastKnownLocation.getLongitude() * 1E6));

                    Point currentPoint = new Point();

                    mapView.getProjection().toPixels(currentGeoPoint, currentPoint);

                    canvas.drawBitmap(rotatedBMP, currentPoint.x - (w / 2),
                            currentPoint.y - (h / 2), null);
                }
            }
            return false;
        }

        @Override
        public boolean onTouchEvent(MotionEvent event, MapView mapView) {
            // if we are in record mode save POIs, otherwise no.
            if (applicationMode == Constants.APPLICATION_MODE_RECORD) {
                // ---when user lifts his finger---
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (2000 < SystemClock.uptimeMillis() - event.getDownTime()) {
                        GeoPoint p = mapView.getProjection().fromPixels(
                                (int) event.getX(), (int) event.getY());
                        // Display action Dialog
                        selectedLatitude = p.getLatitudeE6() / 1E6;
                        selectedLongitude = p.getLongitudeE6() / 1E6;

                        showDialog(DIALOG_POI_ID);
                        // debug ==> show lat & long;
                        infoToast.setText(p.getLatitudeE6() / 1E6 + ","
                                + p.getLongitudeE6() / 1E6);
                        infoToast.show();
                    }
                }
            }
            return false;
        }
    }

    // MapOverlay END

    /**
     * Class used to determinate the GPS location.
     */
    private class MyLocationListener implements LocationListener {
        public void onLocationChanged(Location loc) {
            if (loc != null) {
                boolean isFirstTime = false;
                if (lastKnownLocation == null) {
                    // only first time animate to this location.
                    isFirstTime = true;
                }

                Log.i(TAG, "Lat: " + loc.getLatitude() + " Lng: " + loc.getLongitude());
                infoToast.setText("Lat: " + loc.getLatitude() + " Lng: "
                        + loc.getLongitude());
                infoToast.show();

                if (applicationMode == Constants.APPLICATION_MODE_RECORD) {
                    // add the point as intermediate to map points list
                    if (lastKnownLocation == null || mapPoints.isEmpty()) {
                        // this is the first point ==> add it.
                        mapPoints.add(new MapPoint(MapPoint.INTERMEDIATE_POINT, loc));
                    } else {
                        if (loc.distanceTo(lastKnownLocation) > Constants.distanceResolution)
                            mapPoints.add(new MapPoint(MapPoint.INTERMEDIATE_POINT, loc));
                    }

                    if (settings.getString(Constants.PARAM_TOKEN, "").length() > 0) {
                        // we're logged in ==> send current location to server.
                        ContentValues values = new ContentValues();
                        values.put(MySQLiteDBHelper.COLUMN_LAT, loc.getLatitude());
                        values.put(MySQLiteDBHelper.COLUMN_LON, loc.getLongitude());
                        values.put(MySQLiteDBHelper.COLUMN_ALT, loc.getAltitude());
                        values.put(MySQLiteDBHelper.COLUMN_NAME, "");
                        values.put(MySQLiteDBHelper.COLUMN_ROUTE_FILE_NAME,
                                getRouteFileName());
                        values.put(MySQLiteDBHelper.COLUMN_TIME,
                                System.currentTimeMillis());
                        values.put(MySQLiteDBHelper.COLUMN_TYPE,
                                MapPoint.INTERMEDIATE_POINT);

                        Uri cpUri = Uri.withAppendedPath(
                                TransportContentProvider.CONTENT_URI,
                                Uri.encode(MySQLiteDBHelper.SQL_MAIN_TABLE_NAME));
                        getContentResolver().insert(cpUri, values);
                    }
                }

                lastKnownLocation = loc;

                if (isFirstTime)
                    animateToCurrentLocation();
            }
        }

        public void onProviderDisabled(String provider) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
            // This is called when the GPS status alters
            switch (status) {
            case LocationProvider.OUT_OF_SERVICE:
                infoToast.setText("Status Changed: Out of Service");
                infoToast.show();
                break;
            case LocationProvider.TEMPORARILY_UNAVAILABLE:
                infoToast.setText("Status Changed: Temporarily Unavailable");
                infoToast.show();
                break;
            case LocationProvider.AVAILABLE:
                infoToast.setText("Status Changed: Available");
                infoToast.show();
                break;
            }
        }
    }

    /**
     * Handles Dialogs.
     */
    protected AlertDialog onCreateDialog(int id) {
        AlertDialog dialog;
        AlertDialog.Builder builder;
        switch (id) {
        case DIALOG_POI_ID:
            // build add POI dialog
            builder = new AlertDialog.Builder(this);
            builder.setMessage(
                    getString(R.string.add_poi_dialog) + " " + selectedLatitude + ", "
                            + selectedLongitude).setCancelable(false)
                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            // Start Add POI Activity
                            Intent intent = new Intent(MapViewActivity.this,
                                    AddPOIActivity.class);
                            double coordinates[] = { selectedLatitude, selectedLongitude };
                            intent.putExtra(Constants.POI_COORDINATES, coordinates);
                            MapViewActivity.this.startActivityForResult(intent,
                                    ADD_POI_REQUEST);
                        }
                    }).setNegativeButton("No", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });
            dialog = builder.create();

            break;
        default:
            dialog = null;
        }
        return dialog;
    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }

    private final SensorEventListener sensorListener = new SensorEventListener() {
        private float smoothed[] = new float[3];

        private float[] mGravity = new float[3];
        private float[] mGeomagnetic = new float[3];

        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                smoothed = LowPassFilter.filter(event.values, mGravity);
                mGravity[0] = smoothed[0];
                mGravity[1] = smoothed[1];
                mGravity[2] = smoothed[2];
            }
            if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                smoothed = LowPassFilter.filter(event.values, mGeomagnetic);
                mGeomagnetic[0] = smoothed[0];
                mGeomagnetic[1] = smoothed[1];
                mGeomagnetic[2] = smoothed[2];
            }

            if (mGravity != null && mGeomagnetic != null) {
                float R[] = new float[9];
                float I[] = new float[9];
                boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
                        mGeomagnetic);
                if (success) {
                    float remappedR[] = new float[9];
                    success = SensorManager.remapCoordinateSystem(R,
                            SensorManager.AXIS_X, SensorManager.AXIS_Y, remappedR);
                    if (success) {
                        float orientation[] = new float[3];
                        SensorManager.getOrientation(remappedR, orientation);
                        // orientation contains: azimuth, pitch and roll
                        azimuth = orientation[0];

                        mapView.invalidate();
                    }
                }
            }
        }

        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // the magnetic field detector should be calibrated.
            if (Sensor.TYPE_ACCELEROMETER == sensor.getType()
                    || Sensor.TYPE_MAGNETIC_FIELD == sensor.getType()) {
                if (SensorManager.SENSOR_STATUS_UNRELIABLE == accuracy) {
                    infoToast.setText(R.string.magnetic_field_error);
                    infoToast.show();
                }
            }
        }
    };

    @SuppressLint("NewApi")
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map_view);

        animateToMeImageView = (ImageView) findViewById(R.id.animToCurrentLocImageView);
        ImageView settingsImageView = (ImageView) findViewById(R.id.settingsImageView);
        ImageView statsImageView = (ImageView) findViewById(R.id.statsImageView);
        ImageView aboutImageView = (ImageView) findViewById(R.id.aboutImageView);
        ImageView shareImageView = (ImageView) findViewById(R.id.shareImageView);
        LinearLayout actionbarLinearLayout = (LinearLayout) findViewById(R.id.actionbarLinearLayout);

        // Action bar section
        // compute the padding of the images in the action bar
        Display display = getWindowManager().getDefaultDisplay();
        Point screenSize = new Point();
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
            // getSize not available in older SDKs
            screenSize.set(display.getWidth(), 0);
        } else {
            display.getSize(screenSize);
        }
        int padding = (screenSize.x - (getResources().getDrawable(R.drawable.settings)
                .getMinimumWidth() * actionbarLinearLayout.getChildCount()))
                / (actionbarLinearLayout.getChildCount() * 2);

        settingsImageView.setPadding(padding, padding / 4, padding, padding / 4);
        statsImageView.setPadding(padding, padding / 4, padding, padding / 4);
        shareImageView.setPadding(padding, padding / 4, padding, padding / 4);
        aboutImageView.setPadding(padding, padding / 4, padding, padding / 4);

        // set callbacks for the action bar shortcuts
        settingsImageView.setOnClickListener(this);
        statsImageView.setOnClickListener(this);
        shareImageView.setOnClickListener(this);
        aboutImageView.setOnClickListener(this);
        animateToMeImageView.setOnClickListener(this);

        // create the bitmaps and keep them in memory.
        bmpIntermediatePoint = BitmapFactory.decodeResource(getResources(),
                R.drawable.mark);
        bmpPOIHut = BitmapFactory.decodeResource(getResources(), R.drawable.cabana);
        bmpPOIPeak = BitmapFactory.decodeResource(getResources(), R.drawable.mountaintop);
        bmpPOICamping = BitmapFactory.decodeResource(getResources(), R.drawable.camping);
        bmpPOIShelter = BitmapFactory.decodeResource(getResources(), R.drawable.shelter);
        bmpPOINiceToView = BitmapFactory.decodeResource(getResources(),
                R.drawable.nice_to_view);
        bmpCurrentLocation = BitmapFactory.decodeResource(getResources(),
                R.drawable.current_location);

        mPaint.setDither(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(3);
        mPaint.setAntiAlias(true);

        // Init the toast.
        infoToast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);

        // get the points from the GPX file
        routeFilePath = PointsToGPX.getTheRouteFilePath();
        reinitMapPointsFromFile(routeFilePath);
    }

    @Override
    public void onResume() {
        super.onResume();

        settings = Prefs.get();

        timeResolution = settings.getInt(Constants.TIME_RESOLUTION, 60); // seconds
        applicationMode = (byte) settings.getInt(Constants.APPLICATION_MODE,
                Constants.APPLICATION_MODE_RECORD);

        mDrawRoute = settings.getBoolean(Constants.DRAW_ROUTE_STATUS, true);

        mapView = (MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);

        // initialize the GPS manager
        lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        // use this in case GPS permissions are present. Currently not needed.
        Criteria criteria = new Criteria();
        criteria.setAltitudeRequired(true);
        provider = lm.getBestProvider(criteria, true);

        locationListener = new MyLocationListener();

        mapController = mapView.getController();

        // if the route file has changed build the mapPoints list again.
        String newRouteFilePath = PointsToGPX.getTheRouteFilePath();
        if (routeFilePath == null || !routeFilePath.equals(newRouteFilePath)) {
            routeFilePath = newRouteFilePath;
            reinitMapPointsFromFile(routeFilePath);
        }

        mapController.setZoom(DEFAULT_ZOOM_LEVEL);
        mapOverlay = new MapOverlay();

        List<Overlay> listOfOverlays = mapView.getOverlays();
        listOfOverlays.clear();
        listOfOverlays.add(mapOverlay);

        boolean myLocOverlayStatus = settings.getBoolean(Constants.MY_LOC_OVERLAY_STATUS,
                false);
        if (myLocOverlayStatus) {
            try {
                // Use native compass & my location indicators.
                myLocOverlay = new MyLocationOverlay(this, mapView);
                myLocOverlay.enableCompass();
                myLocOverlay.enableMyLocation();
                listOfOverlays.add(myLocOverlay);
            } catch (Exception e) {
                // some phones don't support this
                // if it happens remove this ability.
                Editor editor = settings.edit();
                editor.putBoolean(Constants.MY_LOC_OVERLAY_STATUS, false);
                editor.commit();
                myLocOverlayStatus = false;

                infoToast.setText(R.string.my_loc_overlay_error);
                infoToast.show();
            }
        }

        if (!myLocOverlayStatus) {
            // this means that the user didn't select the native compass.
            mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

            accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

            // Compass:
            if (mSensorManager != null) {
                mSensorManager.registerListener(sensorListener, accelerometer,
                        (int) SensorManager.SENSOR_DELAY_GAME);
                mSensorManager.registerListener(sensorListener, magnetometer,
                        (int) SensorManager.SENSOR_DELAY_GAME);
            }
        }

        satelliteStatus = settings.getBoolean(Constants.SATELLITE_STATUS, false);
        mapView.setSatellite(satelliteStatus);

        animateToMeImageView.setBackgroundColor(satelliteStatus ? Color.LTGRAY
                : Color.TRANSPARENT);

        // TODO: add select provider option in settings
        // send the notifications at a specified time and distance resolution.
        try {
            lm.requestLocationUpdates((provider != null) ? provider
                    : LocationManager.NETWORK_PROVIDER, (timeResolution * 1000),
                    Constants.distanceResolution, locationListener);
        } catch (Exception e) {
            Log.e(TAG, "Cannot determine location: " + e.toString());
        }

        // to be sure register the ContentProvider Observer, it's no problem if
        // it's already registered.
        NetworkUtilities.registerTransportContentObserver();

        // redraw the map
        mapView.invalidate();
    }

    @Override
    public void onPause() {
        super.onPause();

        // remove the location listener, else it consumes battery too much
        lm.removeUpdates(locationListener);

        if (mSensorManager != null)
            mSensorManager.unregisterListener(sensorListener);

        if (myLocOverlay != null && myLocOverlay.isMyLocationEnabled()) {
            myLocOverlay.disableMyLocation();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        // when exit this activity flush the points in the xml file
        if (applicationMode == Constants.APPLICATION_MODE_RECORD) {
            // TODO : do this using the content provider.
            PointsToGPX.addPointsToFile(routeFilePath, mapPoints);
        }

        // unregister the ContentProvider Observer
        NetworkUtilities.unregisterTransportContentObserver();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == ADD_POI_REQUEST) {
            if (resultCode == RESULT_OK) {
                // a poi was added ==> get the coordinates and poi type.
                int poiType = data.getIntExtra(Constants.POI_TYPE,
                        MapPoint.POI_NICE_TO_VIEW);
                double[] poiCoordinates = data
                        .getDoubleArrayExtra(Constants.POI_COORDINATES);
                String poiName = data.getStringExtra(Constants.POI_NAME);

                MapPoint poi = new MapPoint(poiType, poiCoordinates[0],
                        poiCoordinates[1], 0, System.currentTimeMillis(), poiName);

                // add the poi on the map;
                mapPoints.add(poi);
                mapView.invalidate();

                // do the following only if logged in.
                if (settings.getString(Constants.PARAM_TOKEN, "").length() > 0) {
                    // push the point into the content provider
                    // after that it is sent to server.
                    ContentValues values = new ContentValues();
                    values.put(MySQLiteDBHelper.COLUMN_LAT, poiCoordinates[0]);
                    values.put(MySQLiteDBHelper.COLUMN_LON, poiCoordinates[1]);
                    values.put(MySQLiteDBHelper.COLUMN_ALT, 0.0);
                    values.put(MySQLiteDBHelper.COLUMN_NAME, poiName);
                    values.put(MySQLiteDBHelper.COLUMN_ROUTE_FILE_NAME,
                            getRouteFileName());
                    values.put(MySQLiteDBHelper.COLUMN_TIME, System.currentTimeMillis());
                    values.put(MySQLiteDBHelper.COLUMN_TYPE, poiType);

                    Uri cpUri = Uri.withAppendedPath(
                            TransportContentProvider.CONTENT_URI,
                            Uri.encode(MySQLiteDBHelper.SQL_MAIN_TABLE_NAME));
                    getContentResolver().insert(cpUri, values);
                }
            }
        }
    }

    /**
     * Check if the point is in the visible part of the map view
     * 
     * @param mv
     * @param currentPoint
     * 
     * @return
     */
    static private boolean isCurrentLocationVisible(MapView mv, GeoPoint currentPoint) {
        Rect currentMapBoundsRect = new Rect();
        Point currentDevicePosition = new Point();

        mv.getProjection().toPixels(currentPoint, currentDevicePosition);
        mv.getDrawingRect(currentMapBoundsRect);

        return currentMapBoundsRect.contains(currentDevicePosition.x,
                currentDevicePosition.y);
    }

    /**
     * Callback used to handle the click event.
     */
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.animToCurrentLocImageView:
            animateToCurrentLocation();
            break;

        case R.id.settingsImageView:
            openSettingsActivity();
            break;

        case R.id.statsImageView:
            openStatsViewActivity();
            break;

        case R.id.shareImageView:
            // TODO change the extra_text
            Intent i = new Intent(Intent.ACTION_SEND);
            i.setType("text/plain");
            i.putExtra(Intent.EXTRA_SUBJECT,
                    "\'HikingAssistant\' application for Android.");
            i.putExtra(Intent.EXTRA_TEXT,
                    "http://www.hikingassistant.info/index.php?file=my_gpx_test_file.gpx");
            startActivity(Intent.createChooser(i, "Share my route"));

            break;

        case R.id.aboutImageView:
            // TODO Implement this
            infoToast.setText("Not Implemented");
            infoToast.show();
            break;
        }
    }

    /**
     * Animate the map view to last known location.
     */
    private void animateToCurrentLocation() {
        if (lastKnownLocation != null) {
            // display this location in the center of the screen.
            GeoPoint p = new GeoPoint((int) (lastKnownLocation.getLatitude() * 1E6),
                    (int) (lastKnownLocation.getLongitude() * 1E6));
            mapController.animateTo(p);
        } else {
            infoToast.setText(R.string.cannot_determine_location);
            infoToast.show();
        }
    }

    /**
     * Open Settings state.
     */
    protected void openSettingsActivity() {
        Intent intent = new Intent(this, SettingsActivity.class);
        this.startActivity(intent);
    }

    /**
     * Open Statistics state.
     */
    protected void openStatsViewActivity() {
        Intent intent = new Intent(this, StatsActivity.class);
        this.startActivity(intent);
    }

    protected void reinitMapPointsFromFile(String filePath) {
        // load the selected route file
        if (null != filePath) {
            File routeFile = new File(filePath);

            try {
                GPXXMLParser xmlParser = new GPXXMLParser(routeFile.toURI().toString());

                mapPoints = xmlParser.getPoints();
            } catch (Exception e) {
                mapPoints = new ArrayList<MapPoint>();

                e.printStackTrace();
                infoToast.setText(R.string.gpx_parse_error_message);
                infoToast.show();
            }
        }
    }

    protected String getRouteFileName() {
        String ret = "";
        if (routeFilePath == null || routeFilePath.length() == 0)
            return routeFilePath;

        int idx = routeFilePath.lastIndexOf('/');
        if (idx > 0)
            ret = routeFilePath.substring(idx + 1);

        return ret;
    }
}
